// 临时存放effect收集的回调函数
let effectStack = [];
// 存放触发事件
let targetMap = new WeakMap();

function reactive(obj) {
      return new Proxy(obj, {
            get(target, key) {
                  track(target, key);
                  return typeof target[key] === "object"
                        ? reactive(target[key])
                        : target[key];
            },
            set(target, key, value) {
                  target[key] = value;
                  trigger(target, key);
            },
            deleteProperty(target, key) {
                  delete target[key];
                  trigger(target, key);
            },
      });
}

function createReactiveEffect(fn, options) {
      const effect = function reactiveEffect(...args) {
            try {
                  // 将函数push进入effect堆栈中
                  effectStack.push(effect);
                  return fn(...args);
            } catch (error) {
                  console.error(error);
            } finally {
                  effectStack.pop();
            }
      };

      return effect;
}

// 建立数据与回调的依赖:传⼊fn，返回的函数将是响应式的，内部代理的数据发⽣变化，它会再次执⾏
function effect(cb, options) {
      // 封装一个自己能处理错误的函数
      let e = createReactiveEffect(cb);

      // 执行封装的函数进行数据依赖收集
      e(options);
}

// 触发器:根据track()建⽴的映射关系，找到对应响应式函数并执⾏它
function trigger(target, key) {
      let depMap = targetMap.get(target);

      if (!depMap) {
            return;
      }

      let deps = depMap.get(key);
      if (deps) {
            deps.forEach((dep) => {
                  console.log(dep);
                  dep && dep();
            });
      }
}

// 收集器:建⽴响应式函数与其访问的⽬标(target)和键(key)之间的映射关系
function track(target, key) {
      // 获取响应式函数
      let effect = effectStack[effectStack.length - 1];

      let depMap = targetMap.get(target);
      // 判断是否存在
      if (!depMap) {
            depMap = new Map();
            targetMap.set(target, depMap);
      }

      let deps = depMap.get(key);
      if (!deps) {
            deps = new Set();
            depMap.set(key, deps);
      }

      deps.add(effect);
}

// let nativeObj = {
//       key: "哈哈哈",
//       foo: "foo",
// };
// let newData = reactive(nativeObj);

// effect(() => {
//       console.log(newData.key, "effrct");
// });

// newData.key = "测试";
